package org.zj.webview;

import lombok.extern.slf4j.Slf4j;
import org.zj.webview.listener.WebViewStateEventListener;
import org.zj.webview.type.*;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

/**
 * WebView通用接口
 *
 * @author zj
 * @since 2025/3/12
 */
@Slf4j
public final class WebViewApi {

    private static final List<WebViewStateEventListener> STATE_EVENT_LISTENERS = new CopyOnWriteArrayList<>();

    private static final AtomicReference<WebViewState> CURRENT_STATE_EVENT = new AtomicReference<>(WebViewState.NONE);

    private static Thread UI_THREAD;

    private static final byte[] LOOP_LOCK = new byte[0];

    /**
     * 获取当前WebView状态
     *
     * @return
     */
    public static WebViewState getCurrentState() {
        return WebViewApi.CURRENT_STATE_EVENT.get();
    }

    /**
     * 添加WebView2环境设置监听器
     *
     * @param listener
     */
    public static void addStateEventListener(WebViewStateEventListener listener) {
        STATE_EVENT_LISTENERS.add(listener);
    }

    /**
     * 移除WebView2环境设置监听器
     *
     * @param listener
     */
    public static void removeStateEventListener(WebViewStateEventListener listener) {
        STATE_EVENT_LISTENERS.remove(listener);
    }

    /**
     * 触发WebView2环境设置监听器
     *
     * @param event
     */
    private static void fireStateEventListener(WebViewState event) {
        WebViewApi.CURRENT_STATE_EVENT.set(event);
        for (WebViewStateEventListener it : STATE_EVENT_LISTENERS) {
            try {
                it.onStateEvent(event);
            } catch (Exception e) {
                LOGGER.error("fireAppStateEventListener error", e);
            }
        }
    }

    /**
     * 获取当前浏览器版本
     *
     * @return
     */
    public static String getBrowserVersion() {
        checkUIThread();
        return getBrowserVersion_();
    }

    /**
     * 获取当前浏览器版本
     *
     * @return
     */
    public static String getTargetCompatibleBrowserVersion() {
        checkUIThread();
        return getTargetCompatibleBrowserVersion_();
    }

    /**
     * 运行WebView2
     */
    public static void runWebView2Loop() {
        synchronized (LOOP_LOCK) {
            // 防止重入
            if (UI_THREAD == Thread.currentThread()) {
                throw new IllegalStateException("already in loop");
            }
            UI_THREAD = Thread.currentThread();
            try {
                WebViewApi.fireStateEventListener(WebViewState.STARTING);
                WebViewApi.runLater(() -> {
                    WebViewApi.fireStateEventListener(WebViewState.STARTED);
                });
                int ret = WebViewApi.runWebView2Loop_();
                if (ret != 0) {
                    WebViewApi.fireStateEventListener(WebViewState.ERROR);
                }
                WebViewApi.fireStateEventListener(WebViewState.STOPPED);
            } finally {
                UI_THREAD = null;
            }
        }
    }

    /**
     * 运行WebView2
     *
     * @param settings
     */
    public static void setWebView2EnvironmentSettings(WebViewSettings settings) {
        WebViewApi.setWebView2EnvironmentSettings_(settings.toString());
    }

    /**
     * 在UI线程执行
     *
     * @param runnable
     */
    public static void runLater(Runnable runnable) {
        WebViewApi.runOnUI_(new UiTask(runnable));
    }


    /**
     * 在UI线程执行并等待
     *
     * @param runnable
     */
    public static void runAndWait(Runnable runnable) {
        if (isUIThread()) {
            throw new IllegalStateException("do not call runAndWait on the UI thread");
        }
        CountDownLatch latch = new CountDownLatch(1);
        try {
            WebViewApi.runOnUI_(new UiTask.Callback(runnable, latch::countDown));
            latch.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 是否在UI线程
     *
     * @return
     */
    public static boolean isUIThread() {
        return WebViewApi.UI_THREAD == Thread.currentThread();
    }


    /**
     * 是否在UI线程
     *
     * @return
     */
    public static void checkUIThread() {
        if (!isUIThread()) {
            throw new IllegalStateException("not in UI thread");
        }
    }

    /**
     * 获取主窗口id
     *
     * @return
     */
    public static int getMainWindowId() {
        checkUIThread();
        return WebViewApi.getMainWindowId_();
    }

    /**
     * 获取窗口数量
     *
     * @return
     */
    public static int getWindowCount() {
        checkUIThread();
        return WebViewApi.getWindowCount_();
    }

    /**
     * 获取窗口id数组
     *
     * @return
     */
    public static int[] getWindowIds() {
        checkUIThread();
        return WebViewApi.getWindowIds_();
    }

    /**
     * 设置主窗口
     *
     * @param window
     */
    public static void setMainWindow(WebWindow window) {
        checkUIThread();
        WebViewApi.setMainWindow_(window);
    }

    /**
     * 获取主窗口
     *
     * @return
     */
    public static WebWindow getMainWindow() {
        checkUIThread();
        return WebViewApi.getMainWindow_();
    }

    /**
     * 获取窗口
     *
     * @param windowId
     * @return
     */
    public static WebWindow getWindow(int windowId) {
        checkUIThread();
        return WebViewApi.getWindow_(windowId);
    }

    /**
     * 获取窗口
     *
     * @param windowId
     * @return
     */
    public static boolean hasWindow(int windowId) {
        checkUIThread();
        return WebViewApi.hasWindow_(windowId);
    }

    /**
     * 设置日志处理器
     *
     * @param logger
     */
    public static void setLogger(ILogger logger) {
        checkUIThread();
        WebViewApi.setLogger_(logger);
    }

    /**
     * 创建窗口
     *
     * @param windowInfo
     * @return
     */
    public static WebWindow createWindow(WindowInfo windowInfo) {
        checkUIThread();
        String title = windowInfo.getTitle();
        if (title != null && title.length() > 128) {
            throw new IllegalArgumentException("title too long");
        }
        return createWindow_(windowInfo);
    }

    /**
     * 设置日志处理器
     *
     * @param logger
     */
    private static native void setLogger_(ILogger logger);

    /**
     * 设置主窗口
     *
     * @param window
     */
    private static native void setMainWindow_(WebWindow window);

    /**
     * 获取主窗口
     *
     * @return
     */
    private static native WebWindow getMainWindow_();

    /**
     * 获取窗口
     *
     * @param windowId
     * @return
     */
    private static native WebWindow getWindow_(int windowId);

    /**
     * 获取窗口
     *
     * @param windowId
     * @return
     */
    private static native boolean hasWindow_(int windowId);

    /**
     * 获取未使用的随机端口
     *
     * @return 0代表失败
     */
    public static native int getRandomUnusedLocalPort();

    /**
     * 运行WebView2
     */
    private static native int runWebView2Loop_();

    /**
     * 在UI线程执行
     *
     * @param runnable
     */
    private static native void runOnUI_(Runnable runnable);

    /**
     * 设置WebView2环境设置
     *
     * @param json
     */
    private static native void setWebView2EnvironmentSettings_(String json);

    /**
     * 创建窗口
     *
     * @param windowInfo
     * @return
     */
    private static native WebWindow createWindow_(WindowInfo windowInfo);

    /**
     * 获取浏览器版本
     *
     * @return
     */
    private static native String getBrowserVersion_();

    /**
     * 获取兼容的浏览器版本
     *
     * @return
     */
    private static native String getTargetCompatibleBrowserVersion_();

    /**
     * 是否在UI线程
     *
     * @return
     */
    private static native boolean isUIThread_();

    /**
     * 获取主窗口id
     *
     * @return
     */
    public static native int getMainWindowId_();

    /**
     * 获取窗口数量
     *
     * @return
     */
    public static native int getWindowCount_();

    /**
     * 获取窗口id数组
     *
     * @return
     */
    private static native int[] getWindowIds_();

}
